package com.zhan.signalling.entity;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.alicloud.openservices.tablestore.model.DefinedColumnType;
import com.alicloud.openservices.tablestore.model.PrimaryKeyType;
import com.google.common.collect.Lists;
import com.zhan.signalling.annotation.IgnoreField;
import com.zhan.signalling.annotation.IndexColumn;
import com.zhan.signalling.annotation.PrimaryKey;
import com.zhan.signalling.annotation.TableStore;

public class TableStoreBeanDefinition {
	
	private String tableName;
	
	private int timeToLive;
	
	private int maxVersion;
	
	private Class<?> clazz;
	
	private List<Column> columns;
	
	private TableStoreBeanDefinition (Class<?> tableClass) {
		this.clazz = tableClass;
		this.resolver(tableClass);
	}
	
	public static TableStoreBeanDefinition build(Class<?> tableClass) {
		TableStore tableStoreClass = tableClass.getAnnotation(TableStore.class);
		if(tableStoreClass == null) {
			throw new IllegalArgumentException("tableClass is not TableStore, please add annotation");
		}else {
			return new TableStoreBeanDefinition (tableClass);
		}
	}
	
	private void resolver(Class<?> tableClass) {
		
		// 表信息
		TableStore tableStoreClass = tableClass.getAnnotation(TableStore.class);
		this.tableName = tableStoreClass.name();
		this.timeToLive = tableStoreClass.timeToLive();
		this.maxVersion = tableStoreClass.maxVersions();
		
		// 列信息
		columns = new ArrayList<>();
		Field[] fields = tableClass.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			IgnoreField ignoreField = field.getAnnotation(IgnoreField.class);
			if(ignoreField != null) {
				continue;
			}
			PrimaryKey primaryKey = field.getAnnotation(PrimaryKey.class);
			IndexColumn indexColumn = field.getAnnotation(IndexColumn.class);
			if(primaryKey != null) {
				columns.add(new Column(primaryKey.name(),field.getClass(),true,primaryKey.order()));
				continue;
			}
			if(indexColumn != null) {
				columns.add(new Column(indexColumn.name(),field.getClass(),true,indexColumn.indexName(),
						Lists.newArrayList(indexColumn.primaryKey())));
				continue;
			}
			columns.add(new Column(field.getName(), field.getClass()));
		}
		// 排序列，将主键按顺序排列
		Collections.sort(columns);
	}
	
	public class Column implements Comparable<Column>{
		
		private String name;
		
		private Class<?> clazz;
		
		/**
		 * No Support: isPrimaryKey equal isIndexCloumn equal true
		 */
		private boolean isPrimaryKey;
		
		private boolean isIndexColumn;
		/**
		 * isIndexCloumn = true 时
		 */
		private String indexName;
		
		/**
		 * 索引关联的主键,注意顺序
		 */
		private List<String> associationPrimaryKey;
		
		private int order;
		
		public Column(String name, Class<?> clazz) {
			this(name,clazz,false,99999);
		}

		public Column(String name, Class<?> clazz, boolean isPrimaryKey,int order) {
			this.name = name;
			this.clazz = clazz;
			this.isPrimaryKey = isPrimaryKey;
			this.order = order;
		}

		public Column(String name, Class<?> clazz, boolean isIndexCloumn, String indexName, List<String> associationPrimaryKey) {
			super();
			this.name = name;
			this.clazz = clazz;
			this.isIndexColumn = isIndexCloumn;
			this.indexName = indexName;
			this.associationPrimaryKey = associationPrimaryKey;
		}
		
		public PrimaryKeyType getPKType(Class<?> type) {
			if(Long.class.getName().equals(type.getName()) 
					&& Long.class.getPackage().equals(type.getPackage())) {
				return PrimaryKeyType.INTEGER;
			}else if(Integer.class.getName().equals(type.getName()) 
					&& Integer.class.getPackage().equals(type.getPackage())) {
				return PrimaryKeyType.INTEGER;
			}else if(String.class.getName().equals(type.getName()) 
					&& String.class.getPackage().equals(type.getPackage())) {
				return PrimaryKeyType.STRING;
			}else {
				throw new IllegalArgumentException("tableStore PrimaryKeyType is wrong, only support Long, Integer, String");
			}
		}
		
		public DefinedColumnType getDefinedColumnType(Class<?> type) {
			if(Long.class.getName().equals(type.getName()) 
					&& Long.class.getPackage().equals(type.getPackage())) {
				return DefinedColumnType.INTEGER;
			}else if(Integer.class.getName().equals(type.getName()) 
					&& Integer.class.getPackage().equals(type.getPackage())) {
				return DefinedColumnType.INTEGER;
			}else if(String.class.getName().equals(type.getName()) 
					&& String.class.getPackage().equals(type.getPackage())) {
				return DefinedColumnType.STRING;
			}else if(Double.class.getName().equals(type.getName()) 
					&& Double.class.getPackage().equals(type.getPackage())) {
				return DefinedColumnType.DOUBLE;
			}else if(Boolean.class.getName().equals(type.getName()) 
					&& Boolean.class.getPackage().equals(type.getPackage())) {
				return DefinedColumnType.BOOLEAN;
			}else {
				throw new IllegalArgumentException("tableStore DefinedColumnType is wrong, only support Long, Integer, String, Double, Boolean");
			}

		}
		
		@Override
		public int compareTo(Column o) {
			return this.order - o.getOrder();
		}

		public List<String> getAssociationPrimaryKey() {
			return associationPrimaryKey;
		}

		public String getName() {
			return name;
		}

		public Class<?> getClazz() {
			return clazz;
		}

		public boolean isPrimaryKey() {
			return isPrimaryKey;
		}

		public boolean isIndexColumn() {
			return isIndexColumn;
		}

		public int getOrder() {
			return order;
		}

		public String getIndexName() {
			return indexName;
		}
		
	}

	public String getTableName() {
		return tableName;
	}

	public int getTimeToLive() {
		return timeToLive;
	}

	public int getMaxVersion() {
		return maxVersion;
	}

	public Class<?> getClazz() {
		return clazz;
	}

	public List<Column> getColumns() {
		return columns;
	}
	
}
